package MAIN;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
//笔试强训第31天
//选择题
/*目前实现线程同步的方法有很多，其中包括临界区，互斥量，事件，信号量四种方式
* 临界区：通过多线程的串行化来访问公共资源或一段代码（临界区可以认为是操作共享资源的一段代码）
* 互斥量：为协调共同对一个共享资源的单独访问而设计的
* 信号量：多个线程来同时执行一段代码，如最多有5个线程来同时执行这段代码，此时5个或5个一下的
* 线程数是可以的，就是不能超过5个
* 事件：类似于进程间的通信，用来通知线程有一些事件已发生，从而启动后继任务的开始*/
/*可重入函数：主要用于多任务中，一个可重入的函数就是可以被中断的函数，也就是说可以再这个函数
执行的任何时刻中断他，转入操作系统调度下去执行另外一段代码，而返回时不会出现什么错误
不可重入函数：由于使用了喜喜呃系统资源，比如全局变量区，中断向量表，所以如果他被中断的话，可能会
出现问题，这类函数就不能再多任务环境下运行。
自动变量：就是局部变量，定义的时候运行的时候被创建，函数返回时，就被回收了，是属于线程私有的
所以实现可重入函数时，对自动变量不用互斥量加以保护，因为他是属于线程私有的*/
/*可重入函数是不可以调用不可重入函数的，如果是可以调用的，此时整体就是不能被中断的函数*/
/*资源循环等待: 多个线程访问同一个资源，此时互相持有对方申请的资源，此时可能会死锁
* 程序内存访问越界：此时可能会引起其他进程也跟着一起崩溃
* 进程释放资源：一个进程持有了一把锁，也就是对一个对象进行加锁之后又解锁，此时就是进程释放资源*/
/*大端模式：是指数据的高字节保存在内存的低地址中，数据的低字节保存在内存的高地址中，如0x12345678用大端模式
* 就是 低位地址 0x12 0x34 0x56 0x78 高位地址
* 小端模式：是指数据的高字节保存在内存的高地址中，而数据的低字节保存在内存的低地址中，如0x12345678
* 用小端模式就是 地位地址 0x78 0x56 0x34 0x12 高位地址*/
/*大端模式就是符合我们的阅读模式，小端模式就是反着来的*/
/*读取硬盘的数据的时间消耗主要是由寻道时间，数据传输时间，还有旋转时间三部分时间组成，所以一次寻道时间肯定是
* 小于从硬盘上读取一次数据的时间的*/
/*分页式虚拟存储系统：将内存要操作的数据信息放在磁盘这里，当作业被调度执行时，并不把作业的程序和数据全部装入
* 主存，而仅仅装入需要立即使用的一些页面，而且至少将作业的第一页装入主存，在执行过程中访问不到的页面再把他们
* 动态装入。  请页式：当需要执行某条指令或者使用某个数据时，发现他们并不在主存中，产生了一个缺页中断，就像读一本书
* 一个概念不理解需要借助另一本书中的某一页才可以理解，此时就是缺页中断，所以：进入内存的页面时没有变化的
* 所以分页式虚拟存储管理系统，页面大小和可能产生的额缺页中断次数无关。*/
/*一个父进程可以创建多个子进程，一个子进程只能属于一个父进程*/
/*子进程和父进程没有必然的依赖关系，子进程被撤销，父进程还可以继续存在，父进程被撤销了，子进程也可以继续存在
*一个进程可以没有父进程或者子进程 */

//编程题
public class Main31 {
    //分解因数：输出分解因数后的因子(因子都必须是素数)
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        while (scan.hasNextInt()) {
            int num = scan.nextInt();
            List<String> factors = factorization(num);
            System.out.printf("%d = %s\n", num, String.join(" * ", factors));
        }
    }
    public static List<String> factorization(int num){
        List<String> list = new ArrayList<>();
        for (int i = 2; i*i <= num && num > 1; i++) {
            while (num % i == 0) {
                list.add(String.valueOf(i));
                num /= i;
            }
        }
        //说明num本身就是一个素数
        if (num > 1) {
            list.add(String.valueOf(num));
        }
        return list;
    }

    //美国节日
    private static boolean isLeapYear(int y) {
        return ((y % 400 == 0) || (y % 4 == 0 && y % 100 != 0));
    }

    private static final int[] DAYS = {31,28,31,30,31,30,31,31,30,31,30,31};
    //给定y，m，d，返回这年经过多少天了
    private static int nDays(int y, int m, int d) {
        //m：12   //[0, 10]
        int n = d;
        for (int i = 0; i < m-1; i++) {
            n += DAYS[i];
        }
        //如果m是大于2月的情况下才需要考虑闰年的情况
        if (m > 2 && isLeapYear(y)) n++;
        return n;
    }

    //传入年月日，找到从公元前1年12月31日开始过了多久了，求出它的MOD 7 的同余数
    private static int diff(int y, int m, int d) {
        return (y-1) + (y-1)/4 - (y-1)/100 + (y-1)/400 + nDays(y,m,d);
    }

    //根据年月日求出星期几
    private static int week(int y, int m, int d) {
        int w = diff(y, m, d) % 7;
        if (w == 0) {
            w = 7;
        }
        return w;
    }
    //根据1号是星期x，求第n个星期e是几号
    private static int m1(int w, int n, int e) {
        return 1 + (n-1) * 7 + (7 - w + e) % 7;
    }
    //根据6月1日星期w，求5月的最后一个星期1
    private static int m2(int w) {
        int d = (w == 1 ? 7 : w-1);
        return 32 - d;
    }
    public static void main1(String[] args) {
        Scanner scan = new Scanner(System.in);
        while (scan.hasNextInt()) {
            int y = scan.nextInt();
            System.out.printf("%d-01-01\n", y);
            int w;
            w = week(y, 1, 1);
            System.out.printf("%d-01-%02d\n", y, m1(w, 3, 1));
            w = week(y, 2, 1);
            System.out.printf("%d-02-%02d\n", y, m1(w, 3, 1));
            w = week(y, 6, 1);
            System.out.printf("%d-05-%02d\n", y, m2(w));
            System.out.printf("%d-07-04\n", y);
            w = week(y, 9, 1);
            System.out.printf("%d-09-%02d\n", y, m1(w, 1, 1));
            w = week(y,11,1);
            System.out.printf("%d-11-%02d\n",y, m1(w, 4, 4));
            System.out.printf("%d-12-25\n", y);
            System.out.println();
        }
    }
}
